package com.lihaozhe.orderservice.config;

import feign.Logger;
import feign.codec.ErrorDecoder;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.core5.util.Timeout;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;

/**
 * Feign全局配置类
 * 可以配置连接超时、日志级别、错误处理等
 * <p>
 * 开发思路和开发过程：
 * 1. 配置Feign的日志级别，便于调试和监控Feign调用过程
 * 2. 自定义错误解码器，统一处理Feign调用异常情况
 * 3. 配置HTTP客户端连接池，提高请求性能和资源利用率
 * 4. 设置连接超时和读取超时时间，增强系统稳定性
 * 5. 集成Apache HttpClient5作为底层HTTP客户端实现
 *
 * @author 李昊哲
 * @version 1.0.0
 */
@Configuration
public class FeignConfig {

  /**
   * 配置Feign日志级别
   * NONE: 不记录任何日志
   * BASIC: 仅记录请求方法、URL、响应状态码及执行时间
   * HEADERS: 记录基本信息及请求和响应头信息
   * FULL: 记录请求和响应的完整信息包括头信息、正文和元数据
   *
   * @return Logger.Level 日志级别
   */
  @Bean
  public Logger.Level feignLoggerLevel() {
    return Logger.Level.FULL;
  }

  /**
   * 自定义Feign错误解码器
   * 处理HTTP错误响应，转换为业务异常
   * 用于处理Feign调用失败时的错误信息
   *
   * @return ErrorDecoder 错误解码器实例
   */
  @Bean
  public ErrorDecoder errorDecoder() {
    return (methodKey, response) -> {
      // 根据HTTP状态码处理不同类型的错误
      return switch (response.status()) {
        case 400 -> new IllegalArgumentException("请求参数错误");
        case 404 -> new RuntimeException("请求资源不存在");
        case 500 -> new RuntimeException("服务器内部错误");
        default -> new RuntimeException("Feign调用异常，状态码：" + response.status());
      };
    };
  }

  /**
   * 配置Apache HttpClient连接池
   * 提高HTTP请求性能，避免频繁创建和销毁连接
   *
   * @return PoolingHttpClientConnectionManager 连接池管理器
   */
  @Bean
  public PoolingHttpClientConnectionManager poolingHttpClientConnectionManager() {
    PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
    // 设置最大连接数
    connectionManager.setMaxTotal(200);
    // 设置每个路由的最大连接数
    connectionManager.setDefaultMaxPerRoute(20);
    return connectionManager;
  }

  /**
   * 配置CloseableHttpClient实例
   * 使用连接池管理器和超时设置
   *
   * @param connectionManager 连接池管理器
   * @return CloseableHttpClient HTTP客户端实例
   */
  @Bean
  public CloseableHttpClient closeableHttpClient(PoolingHttpClientConnectionManager connectionManager) {
    // 配置连接参数
    RequestConfig requestConfig = RequestConfig.custom()
        .setResponseTimeout(Timeout.ofDays(30000))   // 读取超时时间30秒
        .build();

    return HttpClients.custom()
        .setConnectionManager(connectionManager)
        .setDefaultRequestConfig(requestConfig)
        .build();
  }

  /**
   * 配置HttpComponentsClientHttpRequestFactory
   * 将自定义的HttpClient集成到Spring中
   *
   * @param httpClient Apache HttpClient实例
   * @return HttpComponentsClientHttpRequestFactory 请求工厂
   */
  @Bean
  public HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory(
      CloseableHttpClient httpClient) {
    HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
    factory.setHttpClient(httpClient);
    // 设置连接超时时间(毫秒)
    factory.setConnectTimeout(5000);
    // 设置读取超时时间(毫秒)
    factory.setReadTimeout(30000);
    return factory;
  }
}
